
#include <stdio.h>

#ifndef __WIN32__
#include <unistd.h>
#include <apr_signal.h>
#define KEYONSIGNAL SIGINT
#endif

#include "aprtools/APRPRNG.h"
#include "iface/APRInterface.h"
#include "iface/SQLiteInterface.h"
#include "iface/SSLInterface.h"

#include "db/ActorsDB.h"
#include "db/KeyDB.h"
#include "db/PendingDB.h"
#include "db/NetworkDBFromXML.h"

#include "net/BrokerMessage.h"
#include "net/Broker5Server.h"
#include "net/BlockWriteServer.h"
#include "utils/Prompt.h"

#include "default_hosts.h"
#include "acquire_config.h"

int allstop;

// Remember to describe this function in documentation! - useful for gdb
#ifndef __WIN32__
/** This function is useful for stopping the program while inside GDB.
 * It is actually used for catching the signal SIGTERM and stopping the
 * program, but using 'inspect signal_setflag(2)' inside gdb also
 * triggers a full stop. This way databases are dumped in human-readable
 * SQL, enabling better debugging.
 * 
 * @param signo
 * The number of the signal sent to this signal handler. */
void signal_setflag(int signo)
{
   printf("Received signal (%d ? %d)\n", signo, KEYONSIGNAL);
   if (signo == KEYONSIGNAL)
      allstop = 1;
}
#endif

int main(int argc, const char *argv[])
{
   putARGV0ToGlobalPlace(argv[0]);
   int nargc = argc;
   const char *const *nargv = argv;
   APRInterface apr_iface = APRInterface::getInstance(&nargc, &nargv);
   SSLInterface ssl_iface = SSLInterface::getInstance();
   SQLiteInterface sqlite_iface = SQLiteInterface::getInstance();
   allstop = 0;
#ifndef __WIN32__
   apr_sigfunc_t *sighandler = apr_signal(KEYONSIGNAL, &signal_setflag);
#endif
//   Prompt pr(NULL);
#ifdef USE_BUILTIN_INSECURE_PASSWORDS
   Prompt pr("hello2");
   Prompt prbroker("broker");
#else
   Prompt pr(NULL);
   Prompt prbroker(NULL);
#endif

   char *wip = const_cast<char *>(pr.promptForPassword("Work-In-Progress (WIP) password: "));
   char *brokerpwd = const_cast<char *>(prbroker.promptForPassword("Main broker key password: "));
   KeyDB *keydb = new KeyDB(ACQUIRE_DYNAMIC_DIR "/" "broker_keydb", wip, "broker", brokerpwd, 1);
   free(wip);
   free(brokerpwd);
   
   PendingDB *pendingdb = new PendingDB(ACQUIRE_DYNAMIC_DIR "/" "broker_pending");
   ActorsDB *actorsdb = new ActorsDB(ACQUIRE_DYNAMIC_DIR "/" "broker_actors");
   NetworkDB *networkdb = NULL;
#ifndef USE_TEST_CLUSTER
   if (argc == 1)
   {
      networkdb = new NetworkDB(ACQUIRE_DYNAMIC_DIR "/" "broker_network", 1);
   } else if (strcmp(argv[1], "--load-clusters") == 0)
   {
      networkdb = new NetworkDB(ACQUIRE_DYNAMIC_DIR "/" "broker_network", 1);
      NetworkDBFromXML fromxml(argv[2], apr_iface.getGlobalPool());
      fromxml.mergeXMLWithNetworkDB(networkdb);
   } else if (strcmp(argv[1], "--override-clusters-for-this-session") == 0)
   {
      networkdb = new NetworkDB("broker_network", 0);
      NetworkDBFromXML fromxml(argv[2], apr_iface.getGlobalPool());
      fromxml.mergeXMLWithNetworkDB(networkdb);
   }
#else
   networkdb = new NetworkDB("broker_network", 0);
   NetworkDBFromXML fromxml(TEST_CLUSTER_XML, apr_iface.getGlobalPool());
   fromxml.mergeXMLWithNetworkDB(networkdb);
#endif
   AllDBs alldbs;
   alldbs.keydb = keydb;
   alldbs.pendingdb = pendingdb;
   alldbs.actorsdb = actorsdb;
   alldbs.networkdb = networkdb;
   
//   printf("Using directory: %s\n", ACQUIRE_DYNAMIC_DIR);
//   tests::testBrokerSSHIntegration(*keydb, *pendingdb, "127.0.0.1", 22, apr_iface.getGlobalPool(), "")
   printf("Starting broker server...\n");
   // Only 4 threads?
   const char *broker_hostname_to_listen = "0.0.0.0";
   const int broker_portno_to_listen = 10000;
   Broker5Server *tcpserv = new Broker5Server(8, broker_portno_to_listen, broker_hostname_to_listen, apr_iface.getGlobalPool());
   if (strcmp(broker_hostname_to_listen, "0.0.0.0") == 0) broker_hostname_to_listen = "127.0.0.1";
   
   tcpserv->dbs = &alldbs;
   tcpserv->startSessionThreads();
   tcpserv->startListeningThread();
   /*
   printf("Starting block server...\n");
   BlockWriteServer *blkserv = new BlockWriteServer(8, 10001, "0.0.0.0", apr_iface.getGlobalPool(), 0, NULL, 32);
   blkserv->startSessionThreads();
   blkserv->startListeningThread();
   blkserv->startWatchThread();
   */
   printf("Broker is now actively listening on %s TCP port %d\n", broker_hostname_to_listen, broker_portno_to_listen);
   uint64_t heartbeats = 0;
   while (!allstop)
   {
#ifndef __WIN32__
      sleep(1);
#endif
   }
   //delete blkserv;
   delete tcpserv;
   delete alldbs.networkdb;
   delete alldbs.actorsdb;
   delete alldbs.pendingdb;
   delete alldbs.keydb;
   APRPRNG::forceDestruction();
   return 0;
}
